home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1989-1999 Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice, and
- is provided "as is" without warranty of any kind, either expressed or implied.
- The entire risk as to the use of this information is assumed by the user.
-
-
-
- Using the Clipboard Device
-
- by Andy Finkel
-
-
- The clipboard.device is an Exec device designed to be the standard
- method of data exchange between application programs on the Amiga computer.
- The clipboard.device lives in the DEVS: directory of Workbench, and keeps
- its clips in the DEVS:clipboards directory.
-
- The most common use for the clipboard is passing information by cutting it
- from one application and pasting it into another. There are two methods an
- application can use to pass data to the clipboard. The first is to simply
- WRITE the data to the clipboard.device. In this case, the data is held in
- memory until another application (or the same application) asks to READ the
- data. This is simple but uses a lot of memory if the data is large. Also
- it might waste memory if the data cut to the clipboard is not used.
-
- For this reason, the clipboard.device also supports a a POST mechanism. This
- is more complex than just writing the data to the clipboard. To do a POST,
- an application informs the clipboard.device that data is available.
- If that data is later requested from the clipboard by a second application,
- the clipboard sends a message to the first application asking for the POSTed
- information which is then sent. That way, no memory is used unless it is
- really needed.
-
- Of the two methods, POSTing is better but is harder to implement. To keep
- things simple, this article will cover only the WRITE method for using
- the clipboard.
-
-
-
- Clipboard Data
-
- All data on the clipboard should be in IFF format. This allows the data
- to be self-identifying, thus avoiding the need for private formats to be
- established between various applications. Generally, only two types of
- FORMs will be found on the clipboard: FTXT (text) and ILBM (graphics).
- However, other types are possible.
-
- The clipboard.device keeps data in one of two places - memory or disk. If
- an application writes to the clipboard.device the data is copied into memory.
- If there is not enough memory, the data will be copied to disk. When the
- clipboard.device is closed (ie no applications have it open) any data held
- by the clipboard.device is copied into a clip file in the clipboard directory.
- This allows applications to pass data even if both are not active at the same
- time. If this feature is not desired, the last application to have the
- clipboard.device open may perform a reset before closing the clipboard.device.
- Some application writers dislike having the clipboard.device write to disk if
- it contains data when closed.
-
- The clipboard supports multiple data clips. This is not to be confused with
- multiple chunks in a single clip, which allows for different representations of
- the same data. Multiple clips store different data. Applications performing
- cut and paste operations generally specify the primary clip. The alternate
- clips are provided to aid applications in the maintainance of a set of clips
- (ala a scrapbook). The multiple clips are implemented as different units in
- the clipboard device, and are thus accessed at open time.
-
-
-
- Clipboard.device Commands
-
- The commands and their implementation are as follows (the ones I'm going to
- use will be listed first):
-
-
- Read Read data from the clipboard for a paste. io_Offset and
- io_ClipID must be set to zero for the first read of a paste
- sequence. An io_Actual that is less than the io_Length
- indicates that all the data has been read. After all the data
- has been read, a subsequent read must be performed (one whose
- io_Actual returns zero) to indicate to the clipboard device
- that all the data has been read. This allows random access of
- the clip while reading (provided only valid reads are
- performed).
-
- Write Write data to the clipboard for a cut. io_Offset and
- io_ClipID must be set to zero for the first write of a cut
- sequence. An Update command must be given to tell the
- the clipboard that all the data has been written.
-
- Update Indicates that the data provided with a Write command is
- complete, and available for a Read. You cannot issue an
- Update command if any Writes are pending.
-
- Clear Clear the data from this unit. Subsequent Reads will have
- no data available.
-
- Reset Reset the clipboard.device to power-on state without closing
- it. This will also clear all the data.
-
- Stop Service no commands except Invalid, Start, Flush.
-
- Start Resume command servicing.
-
- Flush Abort all pending commands.
-
- Post Post the availability of clip data. io_ClipID must be set to
- zero, a subsequent write of this data does not have io_ClipID
- set to zero as described above, but to the value in io_ClipID
-
- CurrentReadID
- Return the ClipID of the current clip to read.
-
- CurrentWriteID
- Return the ClipID of the latest clip written.
-
-
-
- How To Use the Clipboard.device
-
- To use the clipboard.device, you must set up an IORequest to talk to the
- device. The IORequest structure for the clipboard is called an IOClipReq.
- It is defined in the header file devices/clipboard.h and looks like this:
-
- struct IOClipReq {
- struct Message io_Message;
- struct Device *io_Device; /* device node pointer */
- struct Unit *io_Unit; /* unit (driver private)*/
- UWORD io_Command; /* device command */
- UBYTE io_Flags; /* including QUICK and SATISFY */
- BYTE io_Error; /* error or warning num */
- ULONG io_Actual; /* number of bytes transferred */
- ULONG io_Length; /* number of bytes requested */
- SPTR io_Data; /* either clip stream or post port */
- ULONG io_Offset; /* offset in clip stream */
- LONG io_ClipID; /* ordinal clip identifier */
- }
-
- Notice that this is the same as a standard IO request structure with one
- extra field, io_ClipID. To use the clipboard.device you first Open it by
- passing it the address of an IOClipReq and a clip unit number as follows:
-
- OpenDevice("clipboard.device", unit, &IOClipReq, 0);
-
- The primary clip unit used by applications to share data is unit 0, use of
- alternate clip units is by private convention. After opening the clipboard,
- the IOClipReq must be initialized before doing a cut or paste operation.
-
- When you do a READ or WRITE to the clipboard.device, you must initialize the
- io_ClipID field to 0. The clipboard.device will take care of it from then
- on - the ID is used internally by the clipboard to keep track of clips. You
- must also initialize the io_Offset field to 0; this is used for random access
- READs. By using the offset, you can skip around inside the clip. Only when
- you trigger the end of clip by trying to read past the end does the
- clipboard.device know you are finished with the clip.
-
- The program listed below, CBIO, shows how to use the clipboard.device for
- simple text operations. This code is based on an example by Bob Burns.
-
-
-
- /*********************************************************************/
- /* */
- /* Program name: cbio */
- /* */
- /* Purpose: To provide standard clipboard device interface routines*/
- /* such as Open, Post, Read, Write, etc. */
- /* */
- /*********************************************************************/
- #include "exec/types.h"
- #include "exec/ports.h"
- #include "exec/io.h"
- #include "devices/clipboard.h"
-
-
- struct IOClipReq clipboardIO = 0;
- struct MsgPort clipboardMsgPort = 0;
- struct MsgPort satisfyMsgPort = 0;
-
- int CBOpen(unit)
- int unit;
- {
- int error;
-
- /* open the clipboard device */
- if ((error = OpenDevice("clipboard.device", unit, &clipboardIO, 0)) != 0)
- return(error);
-
- /* Set up the message port in the I/O request */
- clipboardMsgPort.mp_Node.ln_Type = NT_MSGPORT;
- clipboardMsgPort.mp_Flags = 0;
- clipboardMsgPort.mp_SigBit = AllocSignal(-1);
- clipboardMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
- AddPort(&clipboardMsgPort);
- clipboardIO.io_Message.mn_ReplyPort = &clipboardMsgPort;
-
- satisfyMsgPort.mp_Node.ln_Type = NT_MSGPORT;
- satisfyMsgPort.mp_Flags = 0;
- satisfyMsgPort.mp_SigBit = AllocSignal(-1);
- satisfyMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL);
- AddPort(&satisfyMsgPort);
- return(0);
- }
-
- CBClose()
- {
- if(clipboardMsgPort.mp_SigBit >0)FreeSignal(clipboardMsgPort.mp_SigBit);
- if(satisfyMsgPort.mp_SigBit >0)FreeSignal(satisfyMsgPort.mp_SigBit);
- RemPort(&satisfyMsgPort);
- RemPort(&clipboardMsgPort);
- CloseDevice(&clipboardIO);
- }
-
- CBSatisfyPost(string,length)
- char *string;
- int length;
- {
- clipboardIO.io_Offset = 0;
- writeLong("FORM");
- length += 12;
- writeLong(&length);
- writeLong("FTXT");
- writeLong("CHRS");
- length -= 12;
- writeLong(&length);
-
- clipboardIO.io_Command = CMD_WRITE;
- clipboardIO.io_Data = string;
- clipboardIO.io_Length = length;
- DoIO(&clipboardIO);
-
- clipboardIO.io_Command = CMD_UPDATE;
- return(DoIO(&clipboardIO));
- }
-
- writeLong(ldata)
- LONG *ldata;
- {
-
- int status;
- clipboardIO.io_Command = CMD_WRITE;
- clipboardIO.io_Data = ldata;
- clipboardIO.io_Length = 4;
- status=(DoIO(&clipboardIO));
- }
-
- CBCutS(string,length)
- char *string;
- int length;
- {
- clipboardIO.io_ClipID = 0;
- return(CBSatisfyPost(string,length));
- }
-
- int
- CBPasteS(string)
- char *string;
- {
- int length=0,status=0;
-
- clipboardIO.io_Command = CMD_READ; /* get the FORM */
- clipboardIO.io_Data = string;
- clipboardIO.io_Length = 4;
- clipboardIO.io_Offset = 0;
- clipboardIO.io_ClipID = 0;
- status -= DoIO(&clipboardIO);
- string[4]='\0';
-
- if(!strcmp(string,"FORM")) { /* iff form */
- clipboardIO.io_Command = CMD_READ; /* get the total length */
- clipboardIO.io_Data = &length;
- clipboardIO.io_Length = 4;
- status -=DoIO(&clipboardIO);
-
- clipboardIO.io_Command = CMD_READ; /* read the chunk and body */
- clipboardIO.io_Data = string;
- clipboardIO.io_Length = 8;
- status -=DoIO(&clipboardIO);
- string[8]='\0';
-
- if(!strcmp(string,"FTXTCHRS")) {
- clipboardIO.io_Command = CMD_READ; /* get the length of the data */
- clipboardIO.io_Data = &length;
- clipboardIO.io_Length = 4;
- status -=DoIO(&clipboardIO);
-
- clipboardIO.io_Command = CMD_READ;
- clipboardIO.io_Data = string;
- clipboardIO.io_Length = length;
- status -=DoIO(&clipboardIO);
- }
- }
- /* force end of file to terminate read */
- clipboardIO.io_Command = CMD_READ;
- clipboardIO.io_Length = 1;
- clipboardIO.io_Data = 0;
- status -= DoIO(&clipboardIO);
-
- if(!status)return(length);
- else return(-1);
- }
-
-
- int
- CBCurrentReadID()
- {
- clipboardIO.io_Command = CBD_CURRENTREADID;
- DoIO(&clipboardIO);
- return(clipboardIO.io_ClipID);
- }
-
- int
- CBCurrentWriteID()
- {
- clipboardIO.io_Command = CBD_CURRENTWRITEID;
- DoIO(&clipboardIO);
- return(clipboardIO.io_ClipID);
- }
-
-
- BOOL
- CBCheckSatisfy(idVar)
- int *idVar;
- {
- struct SatisfyMsg *sm;
-
- if (*idVar == 0)
- return(TRUE);
- if (*idVar < CBCurrentWriteID()) {
- *idVar = 0;
- return(TRUE);
- }
- if (sm = (struct SatisfyMsg *) GetMsg(&satisfyMsgPort)) {
- if (*idVar == sm->sm_ClipID)
- return(TRUE);
- }
- return(FALSE);
- }
-
- CBCut(stream, length)
- char *stream;
- int length;
- {
- clipboardIO.io_Command = CMD_WRITE;
- clipboardIO.io_Data = stream;
- clipboardIO.io_Length = length;
- clipboardIO.io_Offset = 0;
- clipboardIO.io_ClipID = 0;
- DoIO(&clipboardIO);
- clipboardIO.io_Command = CMD_UPDATE;
- DoIO(&clipboardIO);
- }
-
- int
- CBPost()
- {
- clipboardIO.io_Command = CBD_POST;
- clipboardIO.io_Data = &satisfyMsgPort;
- clipboardIO.io_ClipID = 0;
- DoIO(&clipboardIO);
- return(clipboardIO.io_ClipID);
- }
-
-
-